/***************************************************
 ** Create by Hasaki on 2021/11/27.
 ** This file is part of the CSTL project.
 ** This file follows version 3 of GNU License.
 ** About GNU, see <https://www.gnu.org/licenses/>.
 **
 ** 本文件由Hasaki(间宫羽咲sama)于2021年11月27日创建。
 ** 本文件是CSTL(C-STL)项目的一部分。
 ** 本文件遵从GNU-v3协议。
 ** 关于GNU协议，见<https://www.gnu.org/licenses/>。
 ***************************************************/
#include "HskBuffer.h"
#include "HskLogConfig.h"

Buffer* BufCreate(const size_t capacity) {
  // 尝试初始化buf，分配4个NULL
  Buffer *buf = (Buffer *)calloc(4, sizeof(char *));  // 如果calloc失败，返回NULL并严重警告
  ASSERT_MALLOC_NOT_NULL(buf, printf("[BufCreate CRIT WARN]: Bad calloc of buf, capacity = %zu.\n", capacity), NULL)

  // 尝试给buf分配capacity个typesize的空间，每个初始为0
  if (capacity != 0) {  // capacity为0就不用分配了
    buf->_begin = (char *)calloc(capacity, sizeof(char)); // 如果calloc失败，free(buf)后返回NULL并严重警告
    ASSERT_MALLOC_NOT_NULL(buf->_begin, printf("[BufCreate CRIT WARN]: Bad calloc of buf->_begin, capacity = %zu.\n", capacity);
                                        free(buf);, NULL)
    buf->_read  = buf->_begin;
    buf->_end   = buf->_begin;
    buf->_last  = buf->_begin + capacity;
  }
  return buf;
}

void BufClean(Buffer *_this) {
  ASSERT_THIS_NOT_NULL(_this, "BufClean", , );   // 如果是空指针就不用free了，防止执行_this->_begin

  free(_this->_begin);  // 析构数组
  free(_this);          // 析构Buffer类
}

void BufDelete(Buffer **_pthis) {
  ASSERT_THIS_NOT_NULL(_pthis, "BufDelete", , );

  BufClean(*_pthis);
  *_pthis = NULL;
}

void BufReCapa(Buffer *const _this, size_t newCapa) {
  ASSERT_THIS_NOT_NULL(_this, "BufReCapa", , );   // 如果是空指针，认为是非法操作，必须先Create一个对象

  size_t unreadSize = _this->_end - _this->_read; // 未读空间长度
  size_t newSize = unreadSize > newCapa ? newCapa : unreadSize;
  HSK_LOG_DEBUG(printf("[BufReCapa DEBUG]: unreadSize = %zu, newCapa = %zu, newSize = %zu.\n", unreadSize, newCapa, newSize));

  // newCapa < size意味着数据空间被缩小了，这里报警告方便debug
  HSK_LOG_WARN(
  if (newCapa < unreadSize)
    printf("[BufReCapa WARN]: newCapa %zu < unreadSize %zu, so size will be cropped.\n", newCapa, unreadSize);
  )

  // 如果新容量是0，直接return，避免malloc(0)这种UB
  if (newCapa == 0) {
    free(_this->_begin);
    _this->_begin = NULL;
    _this->_read = NULL;
    _this->_end   = NULL;
    _this->_last  = NULL;
    return;
  }

  // 将Buf(size, capa)扩/缩容为Buf(newSize, newCapa)
  char *newBuf = (char *)calloc(newCapa, sizeof(char));  // 其实用malloc+memcpy开销会更小，但这里偷懒了
  ASSERT_MALLOC_NOT_NULL(newBuf, printf("[BufReCapa CRIT WARN]: Bad calloc of newBuf, capacity = %zu.\n", newCapa), )
  
  memcpy(newBuf, _this->_read, newSize);
  free(_this->_begin);    // 释放旧空间，指向新分配的newBuf
  _this->_begin = newBuf;
  _this->_read  = newBuf;
  _this->_end   = newBuf + newSize;
  _this->_last  = newBuf + newCapa;
}

void BufReSize(Buffer *const _this) {
  ASSERT_THIS_NOT_NULL(_this, "BufReSize", , );   // 如果是空指针，认为是非法操作，必须先Create一个对象

  // 如果begin == read，就没必要清理空间了
  if (_this->_begin != _this->_read) {
    size_t unreadSize = _this->_end - _this->_read;
    size_t readedSize = _this->_read - _this->_begin; // readed表示已读空间，我知道read的过去式还是read
    memmove(_this->_begin, _this->_read, unreadSize);
    memset(_this->_begin + unreadSize, 0, readedSize);
    _this->_end -= readedSize;
    _this->_read = _this->_begin;
  }
}

void BufHandleAll(Buffer *const _this, void (*handle)(Buffer *const, char *, size_t)) {
  ASSERT_THIS_NOT_NULL(_this, "BufHandleAll", , );

  size_t seq = 0;
  char *it  = _this->_begin;
  char *endPtr =  _this->_end;
  // 用<是为了防止_this->end意外改变导致死循环
  while (it != endPtr) {
    handle(_this, it, seq);
    ++ it;
    ++ seq;
    // 该警告用于检查handle函数是否改变了endPtr
    HSK_LOG_WARN(
    if (endPtr != _this->_end) {
      printf("[BufHandleAll WARN]: _this->_end accidently be changed in handle.\n");
      return;
    }
    )
  }
}

void BufPush(Buffer *const _this, const char val) {
  ASSERT_THIS_NOT_NULL(_this, "BufPush", , );

  if (_this->_end == _this->_last) {    // 如果满了
    if (_this->_begin != _this->_read)  // 能腾出地方就ReSize下
      BufReSize(_this);
    else                // 腾不出来就按照2^n向上取整的方式分配空间
      BufReCapa(_this, HskPower2Ceil(_this->_end - _this->_read + 1));
  }
  *_this->_end = val;
  ++ _this->_end;
}

void BufPushSlice(Buffer *const _this, const char *elemBeg, const char *elemEnd) {
  ASSERT_THIS_NOT_NULL(_this, "BufPushSlice", , );

  size_t pushSize = elemEnd - elemBeg;
  size_t unreadSize = _this->_end - _this->_read;
  size_t sweepSize = _this->_read - _this->_begin;

  if (_this->_end + pushSize > _this->_last) {  // 如果空间不够
    // 如果清理出已读空间sweepSize后可以放得下，就Resize下
    if (_this->_end - sweepSize + pushSize <= _this->_last)
      BufReSize(_this);
    else  // 如果清理出来还是不够，就按照2^n向上取整的方式分配空间
      BufReCapa(_this, HskPower2Ceil(unreadSize + pushSize));
  }
  memcpy(_this->_end, elemBeg, pushSize);
  _this->_end += pushSize;
}

void BufReadBuf(Buffer *const _this, Buffer *const buf, const int N) {
  ASSERT_THIS_NOT_NULL(_this, "BufReadBuf-this", , );
  ASSERT_THIS_NOT_NULL(buf, "BufReadBuf-buf", , );

  // 越界检查， 要求N <= unreadSize，否则报参数警告，可通过关闭参数警告不编译这一段，提高效率
  HSK_LOG_PARM_WARN(
  if (N > buf->_end - buf->_read)
    printf("[BufReadBuf PARM WARN]: N %zu > unreadSize %zu is unexpected, capacity = %zu.\n", N, BufGetSize(buf), BufGetCapa(buf));
  )

  BufPushSlice(_this, buf->_read, buf->_read + N);
  buf->_read += N;
}

void BufDelN(Buffer *const _this, const size_t _N) {
  ASSERT_THIS_NOT_NULL(_this, "BufDelN", , );

  char *newEnd = _this->_end - _N;
  if (newEnd <= _this->_read) {  // 相当于全部删除
    HSK_LOG_WARN(printf("[BufDelN WARN]: size %zu but delete %zu, so all space be freed.\n", BufGetSize(_this), _N));
    free(_this->_begin);
    _this->_begin = NULL;
    _this->_read  = NULL;
    _this->_end   = NULL;
    _this->_last  = NULL;
  }
  else {
    memset(newEnd, 0, _this->_end - newEnd);
    _this->_end = newEnd;
  }
}

char* BufGet(const Buffer *const _this, const size_t N) {
  ASSERT_THIS_NOT_NULL(_this, "BufGet", , 0);
  // 越界检查， 要求N < size，否则报参数警告，可通过关闭参数警告不编译这一段，提高效率
  HSK_LOG_PARM_WARN(
  if (N >= _this->_end - _this->_begin)
    printf("[BufGet PARM WARN]: N %zu >= size %zu is unexpected, capacity = %zu.\n", N, BufGetSize(_this), BufGetCapa(_this));
  )
  return _this->_begin + N;
}

char* BufUnreadGet(const Buffer *const _this, const size_t N) {
  ASSERT_THIS_NOT_NULL(_this, "BufUnreadGet", , 0);
  // 越界检查， 要求N < unreadSize，否则报参数警告，可通过关闭参数警告不编译这一段，提高效率
  HSK_LOG_PARM_WARN(
  if (N >= _this->_end - _this->_read)
    printf("[BufGet PARM WARN]: N %zu >= unreadSize %zu is unexpected, capacity = %zu.\n", N, BufGetUnreadSize(_this), BufGetCapa(_this));
  )
  return _this->_read + N;
}

size_t BufGetUnreadSize(const Buffer* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "BufGetUnreadSize", , 0);
  return _this->_end - _this->_read;
}

size_t BufGetSize(const Buffer* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "BufGetSize", , 0);
  return _this->_end - _this->_begin;
}

size_t BufGetCapa(const Buffer* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "BufGetCapa", , 0);
  return _this->_last - _this->_begin;
}

void BufDispMsg(const Buffer* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "BufDispMsg", , );
  printf("this.unreadSize = %zu, this.size = %zu, this.capa = %zu.\n", BufGetUnreadSize(_this), BufGetSize(_this), BufGetCapa(_this));
}

void BufDispAllString(const Buffer* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "BufDispAllString", , );

  HSK_LOG_WARN(
  if (_this->_end == _this->_last && *(_this->_end - 1) != '\0')
    printf("[BufDispAllString WARN]: the end of string not 0, so maybe wrong output.\n");
  )
  printf("this.allString = %s\n", _this->_begin);
}

void BufDispUnreadString(const Buffer* const _this) {
  ASSERT_THIS_NOT_NULL(_this, "BufDispUnreadString", , );

  HSK_LOG_WARN(
  if (_this->_end == _this->_last && *(_this->_end - 1) != '\0')
    printf("[BufDispUnreadString WARN]: the end of string not 0, so maybe wrong output.\n");
  )
  printf("this.unreadString = %s\n", _this->_read);
}

void BufDispAllChar(const Buffer* const _this, const char* beg, const char* const end) {
  ASSERT_THIS_NOT_NULL(beg, "BufDispAllChar", , );

  HSK_LOG_WARN(
  if (beg > end)
    printf("[BufDispAllChar WARN]: beg %zu > end %zu, so loop maybe infinite.\n", beg, end);
  )

  while (beg != end) {
    putchar(*beg);
    ++ beg;
  }
  putchar('\n');
}

void BufDispAllInt(const Buffer* const _this, const char* beg, const char* const end) {
  ASSERT_THIS_NOT_NULL(beg, "BufDispAllInt", , );

  HSK_LOG_WARN(
  if (beg > end)
    printf("[BufDispAllInt WARN]: beg %zu > end %zu, so loop maybe infinite.\n", beg, end);
  )

  while (beg != end) {
    printf("%d ", *beg);
    ++ beg;
  }
  putchar('\n');
}
